ViRC DLL Interface Jesse McGrew June 6, 2001 Introduction ============ ViRC 2.0 can call functions from a DLL, using the /dll command or the $dll() function. Since 2.0pre8, it works with two types of DLLs: mIRC compatible DLLs, which don't stay loaded in memory, and ViRC persistent DLLs, which do. Please note that the C definitions below are provided for convenience only, have not been officially tested, and may be incorrect. mIRC Compatible DLLs ==================== Although not all mIRC DLLs will work in ViRC, the same format as mIRC's DLLs can be used: // Delphi function ProcName(Main, Active: HWND; Data, Params: PChar; Show, NoPause: BOOL): Integer; stdcall; // C int FAR PASCAL procname(HWND main, HWND active, char *data, char *params, BOOL show, BOOL nopause) Main and Active are the window handles of the main ViRC form and the active form (server/channel/query/DCC chat) that invoked the DLL function. Data is used to pass arguments between the DLL and ViRC. Params is only used by ViRC to pass the version number. The DLL can detect whether it was called from ViRC by checking the Params buffer. ViRC initializes it to "ViRC 200", where 200 is the current ViRC build. The DLL function must return a value between 0 and 3: 0 or 1 - no value is returned to the script. ViRC treats 0 and 1 the same. 2 - no value is returned, but the Data buffer contains a command to run before returning to the script. 3 - the Data buffer contains a string to return to the script. Persistent DLLs =============== The $LoadDLL() function loads a persistent DLL and returns a handle. This handle can be used to call procedures from the library, or to unload it: @ $handle = $LoadDLL(fpu.dll) @l $sum = $DLL($handle fadd 1.23 4.56) FreeDLL $handle When ViRC loads a persistent DLL, it calls the VSPersist function: // Delphi function VSPersist(Params: PChar; InitStruct: PDLLInitStruct): Integer; stdcall; // C int FAR PASCAL VSPersist(char *params, DLLINITSTRUCT *initstruct) If the DLL does not export a VSPersist function, it will still be loaded. The InitStruct parameter is a pointer to a TDLLInitStruct structure, which contains information about the client and callback functions for the DLL to use: // Delphi TDLLExecProc = procedure (Text: PChar) stdcall; TDLLParseVarsProc = function (Text, Buffer: PChar; BufSize: Integer): Integer stdcall; TDLLDirectAliasProc = procedure (Token, AliasName, ProcName: PChar) stdcall; PDLLInitStruct = ^TDLLInitStruct; TDLLInitStruct = packed record StructVer, StructSize: Word; ClientBuild, ClientPre: Word; ClientName, DLLToken: packed array[0..15] of Char; MainHWND, ClientHWND: HWND; // callback routines IRCExec: TDLLExecProc; Execute: TDLLExecProc; ParseVars: TDLLParseVarsProc; DirectAlias: TDLLDirectAliasProc; end; // C typedef void FAR PASCAL (*DLLExecProc)(char *text); typedef int FAR PASCAL (*DLLParseVarsProc)(char *text, char *buffer, int bufsize); typedef void FAR PASCAL (*DLLDirectAliasProc)(char *token, char *aliasname, char *procname); typedef struct { WORD StructVer, StructSize; WORD ClientBuild, ClientPre; char ClientName[16], DLLToken[16]; HWND MainHWND, ClientHWND; // callback routines DLLExecProc IRCExec; DLLExecProc Execute; DLLParseVarsProc ParseVars; DLLDirectAliasProc DirectAlias; } DLLINITSTRUCT; StructVer is 1 in ViRC 2.0pre8. ClientBuilt and ClientPre are 200 and 8, respectively. ClientName is "ViRC". DLLToken is a string that identifies this instance of the DLL and can be used with $DLL() or FreeDLL. The VSPersist function should perform any necessary initialization or checks, then return 0 if it failed or nonzero if the DLL should be loaded. If VSPersist returns 0, the DLL will be immediately unloaded. $DLL() uses a different format for persistent DLL calls: // Delphi function p_ProcName(Active: HWND; Channel, Buffer: PChar; BufSize: Integer; Silent: Boolean; Reserved: Pointer): Integer; stdcall; // C int FAR PASCAL p_procname(HWND active, char *channel, char *buffer, int bufsize, BOOL silent, void *reserved) The initial "p_" allows the same DLL to have persistent and non-persistent versions of the same function. $DLL($instance foo) will actually call p_foo. Active is the handle of the active window, and Channel is the active window's name. Buffer is used to pass parameters to and from ViRC. BufSize is the total size of the buffer. Silent is true if text output should be suppressed. Reserved is always nil in 2.0pre8, but may be used in the future. The function must return a value between 0 and 2: 0 - no value is returned to the script. 1 - Buffer contains a string to return to the script. 2 - Buffer contains a string to be returned *and* displayed to the user. Persistent callback functions ============================= IRCExec ------- Usage: IRCExec(PChar(line)); Executes a line of script code. The line will not be evaluated first. It will be run on the global interpreter (OnServer 0). Execute ------- Usage: Execute(PChar(block)); Executes a block of script code, with lines separated by CRLF. Each line will be evaluated, as if the block were part of an alias. The code will be run on the global interpreter. ParseVars --------- Usage: size := ParseVars(PChar(text), buffer, SizeOf(buffer)); Evaluates a string (parsing variable and function references), fills buffer with the result, and returns the total size of the result. The return value may be larger than the supplied buffer size, in which case some of the result will be cut off. The text will be evaluated on the global interpreter. DirectAlias ----------- Usage: DirectAlias(InitStruct^.DLLToken, PChar(aliasname), PChar(dllprocname)); Sets up an alias which, when run, will trigger a call to the DLL. Exactly the same as executing the block of script code: Alias @ $fresult = $DLL( $1-) EndAlias